package cn.cdeden.knowledge.service.impl;

import cn.cdeden.common.core.utils.MapstructUtils;
import cn.cdeden.common.core.utils.page.TableDataInfo;
import cn.cdeden.common.mybatis.validator.QueryHelpMybatisPlus;
import cn.cdeden.common.satoken.utils.LoginHelper;
import cn.cdeden.knowledge.domain.TeamRelevanceRole;
import cn.cdeden.knowledge.domain.TeamRole;
import cn.cdeden.knowledge.domain.dto.*;
import cn.cdeden.knowledge.enums.PermTypeEnum;
import cn.cdeden.knowledge.mapper.TeamFilesTreeMapper;
import cn.cdeden.knowledge.mapper.TeamRelevanceRoleMapper;
import cn.cdeden.knowledge.service.TeamRelevanceRoleService;
import cn.cdeden.knowledge.service.TeamRoleService;
import cn.cdeden.knowledge.utils.PageUtil;
import cn.cdeden.knowledge.utils.TeamUtils;
import cn.cdeden.system.api.RemoteDeptService;
import cn.cdeden.system.api.RemotePostService;
import cn.cdeden.system.api.RemoteRoleService;
import cn.cdeden.system.api.RemoteUserService;
import cn.cdeden.system.api.domain.vo.RemoteDeptVo;
import cn.cdeden.system.api.domain.vo.RemoteJobVo;
import cn.cdeden.system.api.domain.vo.RemoteRoleVo;
import cn.cdeden.system.api.model.LoginUser;
import cn.cdeden.system.api.model.RoleDTO;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.AllArgsConstructor;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * @author Chen
 * @date 2023-11-29
 */
@Service
@AllArgsConstructor
// @CacheConfig(cacheNames = TeamRelevanceRoleService.CACHE_KEY)
@Transactional(propagation = Propagation.SUPPORTS, readOnly = true, rollbackFor = Exception.class)
public class TeamRelevanceRoleServiceImpl extends ServiceImpl<TeamRelevanceRoleMapper, TeamRelevanceRole> implements TeamRelevanceRoleService {

    private final TeamRelevanceRoleMapper teamRelevanceRoleMapper;

    private final TeamRoleService teamRoleService;

    private final TeamFilesTreeMapper teamFilesTreeMapper;

    @DubboReference
    private final RemoteDeptService sysDeptService;
    @DubboReference
    private final RemoteUserService remoteUserService;
    @DubboReference
    private final RemoteRoleService sysRoleService;
    @DubboReference
    private final RemotePostService remotePostService;

//    private final DeptService deptService;

    @Override
    public TableDataInfo<TeamRelevanceRoleDto> queryAll(TeamRelevanceRoleQueryParam query, Pageable pageable) {
        IPage<TeamRelevanceRoleDto> queryPage = PageUtil.toMybatisPage(pageable);

        List<TeamRelevanceRoleDto> teamRelevanceRoleDtoList = teamRelevanceRoleMapper.queryByTreeNodeId(query.getTreeNodeId(), query.getNickName(), pageable.getPageNumber() * pageable.getPageSize(), pageable.getPageSize(), query.getObjectType(), query.getRoleId());
//        QueryWrapper<TeamRelevanceRole> predicate = QueryHelpMybatisPlus.getPredicate(query);
        List<TeamRelevanceRoleDto> teamRelevanceRoleDtos = MapstructUtils.convert(teamRelevanceRoleDtoList, TeamRelevanceRoleDto.class);
        for (TeamRelevanceRoleDto teamRelevanceRoleDto : teamRelevanceRoleDtos) {
            int objectType = teamRelevanceRoleDto.getObjectType();
            //根据类型放入对象名称
            if (objectType == PermTypeEnum.USER.getPermTypeCode()) {
                //用户类型
                teamRelevanceRoleDto.setObjectName(remoteUserService.getUserInfo(teamRelevanceRoleDto.getObjectId()).getNickname());
            }
            if (objectType == PermTypeEnum.DEPT.getPermTypeCode()) {
                //部门类型
                teamRelevanceRoleDto.setObjectName(sysDeptService.getById(teamRelevanceRoleDto.getObjectId()).getDeptName());
            }
            if (objectType == PermTypeEnum.ROLE.getPermTypeCode()) {
                //系统角色类型
                teamRelevanceRoleDto.setObjectName(sysRoleService.getById(teamRelevanceRoleDto.getObjectId()).getRoleName());
            }
            if (objectType == PermTypeEnum.JOB.getPermTypeCode()) {
                //岗位类型
                teamRelevanceRoleDto.setObjectName(remotePostService.getById(teamRelevanceRoleDto.getObjectId()).getName());
            }
            TeamRole teamRole = teamRoleService.getById(teamRelevanceRoleDto.getRoleId());
            teamRelevanceRoleDto.setRoleName(teamRole.getRoleName());
            teamRelevanceRoleDto.setRoleRank(teamRole.getRank());
            teamRelevanceRoleDto.setCreator(teamRelevanceRoleDto.getCreateId());
        }
        int count = teamRelevanceRoleMapper.queryCountByTreeNodeId(query.getTreeNodeId(), query.getNickName(), query.getObjectType(), query.getRoleId());
        queryPage.setTotal(count);
        queryPage.setPages(pageable.getPageNumber());
        queryPage.setSize(pageable.getPageSize());
        queryPage.setRecords(teamRelevanceRoleDtos);
        return MapstructUtils.convertTableDataInfo(TableDataInfo.build(queryPage), TeamRelevanceRoleDto.class);
//        return ConvertUtil.convertPage(queryPage, TeamRelevanceRoleDto.class);
    }

    @Override
    public List<TeamRelevanceRoleDto> queryAll(TeamRelevanceRoleQueryParam query) {
        return MapstructUtils.convert(teamRelevanceRoleMapper.selectList(QueryHelpMybatisPlus.getPredicate(query)), TeamRelevanceRoleDto.class);
    }

    /**
     * @param parentId  继承的上级编号
     * @param newTreeId 需要继承权限的新节点
     * @return 继承的权限对象
     */
    @Override
    public List<TeamRelevanceRoleDto> extendParentPerm(String parentId, String newTreeId) {
        LoginUser user = LoginHelper.getLoginUser();
        List<TeamRelevanceRoleDto> list = new ArrayList<>();
        TeamRoleQueryParam query = new TeamRoleQueryParam();
        QueryWrapper<TeamRelevanceRole> predicate = QueryHelpMybatisPlus.getPredicate(query);
        predicate.eq("tree_node_id", parentId);
        List<TeamRelevanceRole> teamRelevanceRoleList = teamRelevanceRoleMapper.selectList(predicate);
        for (TeamRelevanceRole teamRelevanceRole : teamRelevanceRoleList) {
            TeamRole teamRole = teamRoleService.getById(teamRelevanceRole.getRoleId());
            teamRelevanceRole.setIsExtend(1);
            if (teamRole.getRank() == 1 && !(user.getUserId().equals(teamRelevanceRole.getObjectId()) && teamRelevanceRole.getObjectType().equals(PermTypeEnum.USER.getPermTypeCode()))) {
                //上级文件夹的所有者不是当前用户 则改为仅次于所有者的角色
                List<TeamRoleDto> nextToOwner = teamRoleService.getNextToOwner(teamRelevanceRole.getTeamId());
                if (nextToOwner.size() <= 0)
                    throw new RuntimeException("请设置角色等级仅次于所有者的角色");
                teamRelevanceRole.setRoleId(String.valueOf(nextToOwner.get(0).getId()));
            }else if (teamRole.getRank() == 1 || (user.getUserId().equals(teamRelevanceRole.getObjectId()) && teamRelevanceRole.getObjectType().equals(PermTypeEnum.USER.getPermTypeCode()))){
                //所有者权限单独添加 不在此处处理
                continue;
            }
            TeamRelevanceRoleDto convert = MapstructUtils.convert(teamRelevanceRole, TeamRelevanceRoleDto.class);
            convert.setCreateId(String.valueOf(user.getUserId()));
            convert.setTreeNodeId(newTreeId);
            convert.setId(null);
            insert(convert);
            list.add(convert);
        }

        //添加所有者
        TeamRelevanceRoleDto teamRelevanceOwnerRole = new TeamRelevanceRoleDto();
        teamRelevanceOwnerRole.setIsExtend(0);
        teamRelevanceOwnerRole.setCreateId(String.valueOf(user.getUserId()));
        teamRelevanceOwnerRole.setObjectId(user.getUserId());
        teamRelevanceOwnerRole.setObjectType(PermTypeEnum.USER.getPermTypeCode());
        teamRelevanceOwnerRole.setTeamId(teamRelevanceRoleList.get(0).getTeamId());
        teamRelevanceOwnerRole.setTreeNodeId(newTreeId);
        List<TeamRoleDto> supremeAuthority = teamRoleService.getSupremeAuthority(teamRelevanceOwnerRole.getTeamId());
        if (supremeAuthority.size() <= 0)
            throw new RuntimeException("请设置至少一个管理角色");
        teamRelevanceOwnerRole.setRoleId(String.valueOf(supremeAuthority.get(0).getId()));
        insert(teamRelevanceOwnerRole);
        list.add(teamRelevanceOwnerRole);

        return list;
    }

    @Override
    public TeamRelevanceRole getById(Long id) {
        return teamRelevanceRoleMapper.selectById(id);
    }

    @Override
    public Boolean checkPermission(String treeNodeId, String teamId, LoginUser fileUserDto, String param) {
        List<TeamRelevanceRoleDto> teamRelevanceRoleDtos = getRole(treeNodeId, teamId, fileUserDto);
        boolean b = false;
        for (TeamRelevanceRoleDto teamRelevanceRoleDto : teamRelevanceRoleDtos) {
            TeamRole teamRole = teamRoleService.getById(teamRelevanceRoleDto.getRoleId());
            if (TeamUtils.haveParam(teamRole.getParams(), param)) {
                b = true;
                break;
            }
        }
        return b;

    }

    @Override
    public List<FilesTree> checkPermissionByIds(String teamId, List<String> ids, Long userId, String param) {
        List<TeamRelevanceRole> relevanceRole = getRelevanceRole(teamId, userId, ids);
        List<FilesTree> filesTrees = new ArrayList<>();
        for (TeamRelevanceRole teamRelevanceRole : relevanceRole) {
            TeamRole teamRole = teamRoleService.getById(teamRelevanceRole.getRoleId());
            String treeNodeId = teamRelevanceRole.getTreeNodeId();
            if (TeamUtils.haveParam(teamRole.getParams(), param) && ids.contains(treeNodeId)) {
                filesTrees.add(MapstructUtils.convert(teamFilesTreeMapper.selectById(treeNodeId),FilesTree.class));
            }
        }
        return filesTrees;
    }

    @Override
    public List<TeamRelevanceRoleDto> getRole(String treeNodeId, String teamId, LoginUser fileUserDto) {
        TeamRelevanceRoleQueryParam query = new TeamRelevanceRoleQueryParam();
        QueryWrapper<TeamRelevanceRole> predicate = QueryHelpMybatisPlus.getPredicate(query);
        if (treeNodeId == null) {
            predicate.isNull("tree_node_id");
        } else {
            predicate.eq("tree_node_id", treeNodeId);
        }
        predicate.eq("team_id", teamId);
        List<TeamRelevanceRole> teamRelevanceRoleDtos = teamRelevanceRoleMapper.selectList(predicate);
        List<TeamRelevanceRole> teamRelevanceRoleList = new ArrayList<>();

        for (TeamRelevanceRole teamRelevanceRole : teamRelevanceRoleDtos) {

            //判断用户类型
            if (teamRelevanceRole.getObjectType().equals(PermTypeEnum.USER.getPermTypeCode()) && teamRelevanceRole.getObjectId().equals(fileUserDto.getUserId())) {
                teamRelevanceRoleList.add(teamRelevanceRole);
                continue;
            }
            //判断部门类型
            if (teamRelevanceRole.getObjectType().equals(PermTypeEnum.DEPT.getPermTypeCode())) {
                if (teamRelevanceRole.getObjectId().equals(fileUserDto.getDeptId())) {
                    teamRelevanceRoleList.add(teamRelevanceRole);
                    continue;
                } else {
                    List<RemoteDeptVo> deptDtos = sysDeptService.queryLowerLevel(teamRelevanceRole.getObjectId());
                    //查询出所有下级部门
                    for (RemoteDeptVo deptDto : deptDtos) {
                        if (teamRelevanceRole.getObjectId().equals(deptDto.getDeptId())) {
                            teamRelevanceRoleList.add(teamRelevanceRole);
                        }
                    }
                }
                //判断系统角色类型
                if (teamRelevanceRole.getObjectType().equals(PermTypeEnum.ROLE.getPermTypeCode())) {
                    //获取该用户的所有角色进行判断
                    List<RoleDTO> roles = fileUserDto.getRoles();
                    for (RoleDTO role : roles) {
                        if (teamRelevanceRole.getObjectId().equals(role.getRoleId())) {
                            teamRelevanceRoleList.add(teamRelevanceRole);
                        }
                    }
                }
                //判断岗位类型
                if (teamRelevanceRole.getObjectType().equals(PermTypeEnum.JOB.getPermTypeCode())) {
                    //获取该用户的所有角色进行判断
                    List<Long> jobs = fileUserDto.getPostIds();
                    for (Long jobSmallDto : jobs) {
                        if (teamRelevanceRole.getObjectId().equals(jobSmallDto)) {
                            teamRelevanceRoleList.add(teamRelevanceRole);
                        }
                    }
                }
            }
        }
        return MapstructUtils.convert(teamRelevanceRoleList, TeamRelevanceRoleDto.class);
    }

    @Override
    public List<TeamRelevanceRoleDto> getRelevanceRoleByObject(String treeNodeId, String teamId, Long objectId, Integer objectType) {
        TeamRelevanceRoleQueryParam query = new TeamRelevanceRoleQueryParam();
        QueryWrapper<TeamRelevanceRole> predicate = QueryHelpMybatisPlus.getPredicate(query);
        predicate.eq("tree_node_id", treeNodeId);
        predicate.eq("team_id", teamId);
        predicate.eq("object_id", objectId);
        predicate.eq("object_type", objectType);
        return MapstructUtils.convert(teamRelevanceRoleMapper.selectList(predicate), TeamRelevanceRoleDto.class);
    }

    @Override
    public void updateRole(String treeNodeId, Long userId, Integer objectType, String roleId) {
        teamRelevanceRoleMapper.updateRole(treeNodeId, userId, objectType, roleId);
    }

    @Override
    // @Cacheable(key = "'id:' + #p0")
    public TeamRelevanceRoleDto findById(Long id) {
        return MapstructUtils.convert(getById(id), TeamRelevanceRoleDto.class);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean insert(TeamRelevanceRoleDto resources) {
        TeamRelevanceRole entity = MapstructUtils.convert(resources, TeamRelevanceRole.class);
        return this.save(entity);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateById(TeamRelevanceRoleDto resources) {
        TeamRelevanceRole entity = MapstructUtils.convert(resources, TeamRelevanceRole.class);
        boolean ret = this.updateById(entity);
        // delCaches(resources.id);
        return ret;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean deleteByIds(Set<Long> ids) {
        // delCaches(ids);
        return this.removeByIds(ids);
    }

    /**
     * 获取用户关联的文档
     *
     * @param teamId      团队id
     * @param userId      用户id
     * @param treeNodeIds 在指定的树节点ids中查询
     * @return
     */
    @Override
    public List<TeamRelevanceRole> getRelevanceRole(String teamId, Long userId, List<String> treeNodeIds) {
        //用户类型
        QueryWrapper<TeamRelevanceRole> predicate = QueryHelpMybatisPlus.getPredicate(new TeamRelevanceRoleQueryParam());
        if (teamId != null) {
            predicate.eq("team_id", teamId);
        }
        if (treeNodeIds != null) {
            predicate.in("tree_node_id", treeNodeIds);
        }
        predicate.eq("object_id", userId);
        predicate.eq("object_type", PermTypeEnum.USER.getPermTypeCode());
        Set<TeamRelevanceRole> teamRelevanceRoleHashSet = new HashSet<>(teamRelevanceRoleMapper.selectList(predicate));
        //部门类型
        List<RemoteDeptVo> deptALlByUser = sysDeptService.getDeptALlByUser(userId);
        if (deptALlByUser.size() > 0) {
            predicate = QueryHelpMybatisPlus.getPredicate(new TeamMemberQueryParam());
            // 循环构建或条件
            if (teamId != null) {
                predicate.eq("team_id", teamId);
            }
            if (treeNodeIds != null) {
                predicate.in("tree_node_id", treeNodeIds);
            }
            predicate.and(wrap -> {
                for (int i = 0; i < deptALlByUser.size(); i++) {
                    if (i == 0) {
                        wrap.eq("object_id", deptALlByUser.get(i).getDeptId());
                    } else {
                        wrap.or().eq("object_id", deptALlByUser.get(i).getDeptId());
                    }
                }
            });
            predicate.eq("object_type", PermTypeEnum.DEPT.getPermTypeCode());
            teamRelevanceRoleHashSet.addAll(teamRelevanceRoleMapper.selectList(predicate));
        }
        //系统角色类型
        predicate = QueryHelpMybatisPlus.getPredicate(new TeamMemberQueryParam());
        List<RemoteRoleVo> roleSmallDtos = sysRoleService.selectUserRoleByUserId(userId);
        // 循环构建或条件
        if (roleSmallDtos.size() > 0) {
            if (teamId != null) {
                predicate.eq("team_id", teamId);
            }
            if (treeNodeIds != null) {
                predicate.in("tree_node_id", treeNodeIds);
            }
            predicate.and(wrap -> {
                for (int i = 0; i < roleSmallDtos.size(); i++) {
                    if (i == 0) {
                        wrap.eq("object_id", roleSmallDtos.get(i).getRoleId());
                    } else {
                        wrap.or().eq("object_id", roleSmallDtos.get(i).getRoleId());
                    }
                }
            });
            predicate.eq("object_type", PermTypeEnum.ROLE.getPermTypeCode());
            teamRelevanceRoleHashSet.addAll(teamRelevanceRoleMapper.selectList(predicate));
        }
        //岗位类型
        predicate = QueryHelpMybatisPlus.getPredicate(new TeamMemberQueryParam());
        List<RemoteJobVo> jobDtos = remotePostService.selectUserJobByUserId(userId);
        // 循环构建或条件
        if (jobDtos.size() > 0) {
            if (teamId != null) {
                predicate.eq("team_id", teamId);
            }
            if (treeNodeIds != null) {
                predicate.in("tree_node_id", treeNodeIds);
            }
            predicate.and(wrap -> {
                for (int i = 0; i < jobDtos.size(); i++) {
                    if (i == 0) {
                        wrap.eq("object_id", jobDtos.get(i).getJobId());
                    } else {
                        wrap.or().eq("object_id", jobDtos.get(i).getJobId());
                    }
                }
            });
            predicate.eq("object_type", PermTypeEnum.JOB.getPermTypeCode());
            teamRelevanceRoleHashSet.addAll(teamRelevanceRoleMapper.selectList(predicate));
        }
        return new ArrayList<>(teamRelevanceRoleHashSet);
    }

    @Override
    public List<TeamRelevanceRoleDto> getRelevanceRoleByTreeNodeId(String treeNodeId) {
        return MapstructUtils.convert(teamRelevanceRoleMapper.getRelevanceRoleByTreeNodeId(treeNodeId), TeamRelevanceRoleDto.class);
    }

    @Override
    public void replaceOwnerPerm(Integer teamId,Long userId) {
        teamRelevanceRoleMapper.replaceOwnerPerm(teamId, userId);
    }

    @Override
    public void removeByTreeNodeId(String treeNodeId) {
        teamRelevanceRoleMapper.removeByTreeNodeId(treeNodeId);
    }

    @Override
    public List<TeamRelevanceRole> queryByOwner(String teamId, String objectId) {
        return teamRelevanceRoleMapper.queryByOwner(teamId, objectId);
    }

    @Override
    public void replaceOwnerOtherPerm(String teamId, String oldOwner, String newOwner) {
        teamRelevanceRoleMapper.replaceOwnerOtherPerm(teamId, oldOwner, newOwner);
    }

    @Override
    public void removeExtend(Long treeNodeId, Long objectId) {
        teamRelevanceRoleMapper.removeExtend(treeNodeId, objectId);
    }

    @Override
    public void removeByObjectIds(Integer teamId, Integer permTypeCode, Long objectId) {
        teamRelevanceRoleMapper.removeByObjectIds(teamId,permTypeCode,objectId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean deleteById(Long id) {
        Set<Long> set = new HashSet<>(1);
        set.add(id);
        return this.deleteByIds(set);
    }

    /*
    private void delCaches(Long id) {
        redisUtils.delByKey(CACHE_KEY + "::id:", id);
    }

    private void delCaches(Set<Long> ids) {
        for (Long id: ids) {
            delCaches(id);
        }
    }*/

    /*
    @Override
    public void download(List<TeamRelevanceRoleDto> all, HttpServletResponse response) throws IOException {
      List<Map<String, Object>> list = new ArrayList<>();
      for (TeamRelevanceRoleDto teamRelevanceRole : all) {
        Map<String,Object> map = new LinkedHashMap<>();
              map.put("团队id", teamRelevanceRole.getTeamId());
              map.put("角色id", teamRelevanceRole.getRoleId());
              map.put("树节点id", teamRelevanceRole.getTreeNodeId());
              map.put("用户id", teamRelevanceRole.getUserId());
              map.put("创建者", teamRelevanceRole.getCreateId());
              map.put("创建时间", teamRelevanceRole.getCreateTime());
              map.put("更新者", teamRelevanceRole.getUpdateId());
              map.put("更新时间", teamRelevanceRole.getUpdateTime());
        list.add(map);
      }
      FileUtil.downloadExcel(list, response);
    }*/
}
